package org.codeanalyzer;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import javax.annotation.processing.AbstractProcessor;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

import org.codeanalyzer.model.ApiLibrary;
import org.codeanalyzer.model.ApiPackage;
import org.codeanalyzer.util.Utils;
import org.codeanalyzer.xml.XmlService;

public class ApiAnalyzer
{
    public static void main(String[] args)
    {
        try
        {
            if (args.length < 2)
            {
                System.out.println("Usage: java " + ApiAnalyzer.class.getName()
                    + " <zip_file> <library_name> [-xcom.sun.*,org.corba] [-ofile.name]");
                System.out.println(" zip_file:              zip file containing source code.");
                System.out.println(" library_name:          API library name.");
                System.out.println(" -xcom.sun.*,org.corba: comma separated list of packages to exclude.");
                System.out.println(" -ofile.name:           output xml file");
                System.exit(0);
            }

            String apiLibrayName = getLibraryNameParam(args);
            ApiLibrary apiLibrary = new ApiLibrary(apiLibrayName);
            List<String> excludePackages = getExcludePackages(args);
            if (excludePackages != null)
                apiLibrary.setExcludePackages(excludePackages);

            ApiAnalyzer analyzer = new ApiAnalyzer();
            analyzer.analyzeFromZip(args[0], apiLibrary);
            for(ApiPackage apiPackage : apiLibrary.getPackages())
            {
                System.out.println(String.format("%-40s %3d classes", apiPackage.getName(),
                    apiPackage.getTotalClasses()));
            }
            System.out.println("Analyzing finished. Total packages: " + apiLibrary.getPackages().size()
                + ", total classes: " + apiLibrary.getTotalClasses());

            String outFileName = getOuputFile(args);
            if(outFileName == null)
            	outFileName = apiLibrary.getName() + ".xml";
            File xmlFile = new File(outFileName);

            XmlService xmlService = new XmlService();
            xmlService.save(apiLibrary, xmlFile);
            System.out.println("Analyzed data saved into file: " + xmlFile.getPath());
        }
        catch(Throwable t)
        {
            t.printStackTrace();
        }
    }

    private static String getLibraryNameParam(String[] args)
    {
        return args[1];
    }

    private static List<String> getExcludePackages(String[] args)
    {
        String excludePackages = null;
        if (args.length > 2 && args[2] != null && args[2].startsWith("-x"))
            excludePackages = args[2].substring(2);

        return excludePackages != null ? Arrays.asList(excludePackages.split(",")) : null;
    }

    private static String getOuputFile(String[] args)
    {
        String ouputFile = null;
        for (int i = 2; i <=3; i++) {
        	if (args.length > i && args[i] != null && args[i].startsWith("-o"))
        		ouputFile = args[i].substring(2);
        }
        return ouputFile;
    }

    public void analyzeFromZip(String zipFileName, ApiLibrary apiLibrary) throws IOException
    {
        List<File> files = Utils.extractJavaFilesFromZip(zipFileName);
        System.out.println("Extracted " + files.size() + " source files");

        analyze(files, apiLibrary);
    }

    public void analyze(List<File> sourceFiles, ApiLibrary apiLibrary) throws IOException
    {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);

        try
        {
            Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(sourceFiles);
            // Create the compilation task
            CompilationTask task = compiler.getTask(null, fileManager, null, null, null, compilationUnits);
            // Get the list of annotation processors
            LinkedList<AbstractProcessor> processors = new LinkedList<AbstractProcessor>();
            ApiAnalyzerTreeVisitor visitor = new ApiAnalyzerTreeVisitor(apiLibrary);
            processors.add(new ApiAnalyzerProcessor(visitor));
            task.setProcessors(processors);
            // Perform the compilation task.
            task.call();
        }
        finally
        {
            fileManager.close();
        }
    }
}
